import 'dart:math';

import 'package:flutter/material.dart';
import 'package:kq_flutter_core_widget/widgets/chart/axis/combined/combined_chart.dart';

/// 配置轴相关数据
///
/// Created by wanggaowan on 2023/9/14 16:12
class Axis {
  Axis(
      {this.lineColor = Colors.grey,
      this.lineWidth = 1,
      this.lineDash,
      this.startPadding = 0,
      this.endPadding = 20,
      this.labelCount = 6,
      this.labelTextSize = 12,
      this.labelColor = Colors.black,
      this.labelOffsetAxis = 10,
      this.axisValueFormatter = defaultValueFormatter,
      this.labelAlign = TextAlign.center,
      this.labelOverAlign = TextAlign.left,
      this.labelMaxLines = 1,
      this.textOverflow = TextOverflow.ellipsis,
      this.gridLineColor = Colors.grey,
      this.gridLineWidth = 1,
      this.gridUseEndPadding = false,
      this.gridUseStartPadding = false,
      this.gridLineDash})
      : assert(lineWidth >= 0, "line width must than zero"),
        assert(labelCount > 0, "label count must than zero"),
        assert(labelMaxLines > 0, "label max lines must than zero"),
        assert(gridLineWidth >= 0, "grid line width must than or equals zero");

  /// 轴线颜色
  final Color lineColor;

  /// 轴线宽度
  final double lineWidth;

  /// 绘制虚线时，指定虚实之间的长度。设置此值则轴线为虚线，否则为实线。
  final List<double>? lineDash;

  /// 作用于X轴：左边起始偏移距离。如此值设置为10，那么X轴标签，网格线等数据在X轴都向右偏移10绘制
  ///
  /// 作用于Y轴：底部向上偏移距离。如此值设置为10，那么Y轴标签，网格线等数据在Y轴都向上偏移10绘制
  final double startPadding;

  /// 作用于X轴：右边向左偏移距离。假如X轴轴线长100，此值设置为10，那么轴线标签，网格线等数据可绘制宽度只有90
  ///
  /// 作用于Y轴：顶部向下偏移距离。假如Y轴轴线长100，此值设置为10，那么轴线标签，网格线等数据可绘制高度只有90
  final double endPadding;

  /// 轴上标签数量
  final int labelCount;

  /// 标签值文本大小
  final double labelTextSize;

  /// 标签值颜色
  final Color labelColor;

  /// 标签绘制距离轴线偏移值
  final double labelOffsetAxis;

  /// 标签值格式化
  final AxisValueFormatter axisValueFormatter;

  /// 标签对齐方式
  final TextAlign labelAlign;

  /// 标签超出一行时的对齐方式
  final TextAlign labelOverAlign;

  /// 标签最大行数
  final int labelMaxLines;

  /// 标签超出最大行数后缺省模式，暂不支持[TextOverflow.fade]
  final TextOverflow textOverflow;

  /// 网格线颜色
  final Color gridLineColor;

  /// 网格线宽度(粗细), == 0时则不绘制
  final double gridLineWidth;

  /// [endPadding]属性是否作用于网格线，如果此值为true,那么X轴网格线绘制的高度将<=y轴线高度，y轴网格线绘制的宽度将<=x轴线宽度
  final bool gridUseEndPadding;

  /// [startPadding]属性是否作用于网格线，如果此值为true,那么X轴网格线绘制的高度将<=y轴线高度，y轴网格线绘制的宽度将<=x轴线宽度
  final bool gridUseStartPadding;

  /// 绘制虚线网格时，指定虚实之间的长度。设置此值则网格线为虚线，否则为实线。
  final List<double>? gridLineDash;

  /// 记录绘制的数据
  Rect get drawRect => _drawRect;
  Rect _drawRect = Rect.zero;

  /// 非自定义绘制，请不要主动赋值
  set $drawRect(Rect rect) => _drawRect = rect;

  List<Label>? _labelList;

  /// 格式化后的标签数据
  List<Label>? get labelList => _labelList;

  /// 非自定义绘制, 请不要主动赋值
  set $labelList(List<Label>? list) => _labelList = list;
}

/// 标签，记录标签的文本内容及权重
class Label {
  Label({this.value, this.weight = 1});

  /// 标签值
  final String? value;

  /// 标签权重，数值越大，可绘制区域越大，所有标签默认均分轴线长度。X轴均分宽度，Y轴均分高度。
  /// 以X轴举例，如果[Axis.labelCount]设置为11，则标签共10等份(11个标签两两间只有10个间隔),轴线长200，则每个占20宽度。
  /// 假如某个标签权重设置2，则占40宽度。此时权重为2的标签前后标签如果充满20宽度，则将出现标签重叠。
  /// 一个好的解决方案是11个标签，只绘制偶数6个。如将基数位置权重设置0，偶数设置为2，这样既不会标签绘制太多，
  /// 也保证绘制的标签有足够的空间
  final double weight;
}

/// 格式化轴上指定位置标签
typedef AxisValueFormatter = Label Function(int position);

Label defaultValueFormatter(int position) {
  return Label(value: position.toString());
}

/// 配置X轴相关数据
class BaseXAxis extends Axis {
  BaseXAxis(
      {super.lineColor,
      super.lineWidth,
      super.lineDash,
      super.startPadding,
      super.endPadding,
      super.labelCount,
      super.labelTextSize,
      super.labelColor,
      super.labelOffsetAxis,
      super.axisValueFormatter,
      super.labelAlign,
      super.labelOverAlign,
      super.labelMaxLines,
      super.textOverflow,
      super.gridLineColor,
      super.gridLineWidth,
      super.gridUseEndPadding,
      super.gridUseStartPadding,
      super.gridLineDash,
      this.labelHeight,
      this.labelMinHeight = 0,
      this.labelMaxHeight,
      this.labelHorizontalPadding = 0,
      this.labelRotation = 0})
      : assert(labelHeight == null || labelHeight >= 0,
            "set label height must than or equals zero"),
        assert(
            labelMinHeight >= 0, "label min height must than or equals zero"),
        assert(labelMaxHeight == null || labelMaxHeight >= 0,
            "set label max height must than or equals zero"),
        assert(labelRotation >= 0 && labelRotation < pi,
            "labelRotation value range only in [0,pi)");

  /// 标签绘制区域高度，如果标签绘制时换行超出此高度则裁剪标签.设置为null则根据文本高度及[labelMinHeight]、[labelMaxHeight]自适应
  final double? labelHeight;

  /// 标签绘制区域最小高度
  final double labelMinHeight;

  /// 标签绘制最大高度，超出此值则裁剪标签，设置为null则无限制
  final double? labelMaxHeight;

  /// 两个标签之间的间距
  final double labelHorizontalPadding;

  /// 标签旋转弧度,当此值!=0时，[labelAlign]始终为[TextAlign.left]
  final double labelRotation;
}

/// 配置Y轴相关数据
class BaseYAxis extends Axis {
  BaseYAxis(
      {super.lineColor,
      super.lineWidth,
      super.lineDash,
      super.startPadding,
      super.endPadding,
      super.labelCount,
      super.labelTextSize,
      super.labelColor,
      super.labelOffsetAxis,
      super.axisValueFormatter,
      super.labelAlign = TextAlign.right,
      super.labelOverAlign,
      super.labelMaxLines,
      super.textOverflow,
      super.gridLineColor,
      super.gridLineWidth,
      super.gridUseEndPadding,
      super.gridUseStartPadding,
      super.gridLineDash,
      this.labelWidth,
      this.labelMinWidth = 0,
      this.labelMaxWidth,
      this.labelVerticalPadding = 0})
      : assert(labelWidth == null || labelWidth >= 0,
            "set label width must than or equals zero"),
        assert(labelMinWidth >= 0, "label min width must than or equals zero"),
        assert(labelMaxWidth == null || labelMaxWidth >= 0,
            "set label max width must than or equals zero");

  /// 标签绘制区域高度，如果标签绘制时换行超出此高度则裁剪标签.设置为null则根据文本高度及[labelMinWidth]、[labelMaxWidth]自适应
  final double? labelWidth;

  /// 标签绘制区域最小高度
  final double labelMinWidth;

  /// 标签绘制最大高度，超出此值则裁剪标签，设置为null则无限制
  final double? labelMaxWidth;

  /// 两个标签之间的间距
  final double labelVerticalPadding;

  /// 标签最大行数,如果未设置[labelWidth]或[labelMaxWidth],则始终仅绘制一行
  @override
  int get labelMaxLines => super.labelMaxLines;
}
